// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "GenExpr.hpp"
#include "Gen.hpp"

using namespace ninf::gen;
using namespace ninf::lib;
const char * EXPR_CODE_NAME(GenExprCode code);

GenExpr :: GenExpr(GenExprCode code)
 : 
code(code), lineno(ncGenGlobals.lineno) 
{
  v.lp = NULL;
}

GenExpr :: GenExpr(GenExprCode code, GenExprList * lp) 
  : 
code(code), lineno(ncGenGlobals.lineno)
{
  v.lp = lp;
}

GenExpr :: GenExpr(GenExprCode code, GenSymbol * sym)
  : 
code(code), lineno(ncGenGlobals.lineno)
{
  v.sym = sym;
}

GenExpr :: GenExpr(GenExprCode code, const char * str)
  : 
code(code), lineno(ncGenGlobals.lineno)
{
  v.str = str;
}

GenExpr :: GenExpr(GenExprCode code, long int ival)
  : 
code(code), lineno(ncGenGlobals.lineno)
{
  v.ival = ival;
}

GenExpr :: GenExpr(GenExprCode code, double fval)
  : 
code(code), lineno(ncGenGlobals.lineno)
{
  v.fval = fval;
}

static void
expr_print_rec(FILE * print_fp, GenExpr * x, int l)
{
    int i;
    GenExprList *lp;
    
    /* indent */
    for(i = 0; i < l; i++) fprintf(print_fp,"    ");
    
    if(x == NULL){
      /* special case */
      fprintf(print_fp,"<NULL>");
      return;
    }
    
    fprintf(print_fp,"(%s",EXPR_CODE_NAME(EXPR_CODE(x)));

    fprintf(print_fp,":%d",EXPR_LINENO(x));

    switch (EXPR_CODE(x)){
    case IDENT:
      fprintf(print_fp," \"%s\")",SYM_NAME(EXPR_SYM(x)));
      break;
    case STRING_CONSTANT:
      fprintf(print_fp," \"%s\")",EXPR_STR(x));
      return;
    case INT_CONSTANT:
    case LONG_CONSTANT:
      fprintf(print_fp," %ld)",EXPR_INT(x));
      return;
    case FLOAT_CONSTANT:
      fprintf(print_fp," %g)", EXPR_FLOAT(x));
      return;
    case BASIC_TYPE_NODE:
      fprintf(print_fp," <%s>)", DataNames[(int)EXPR_TYPE(x)]);
      return;
    case MODE_SPEC_NODE:
      fprintf(print_fp," <%s>)", ModeNames[(int)EXPR_MODE_SPEC(x)]);
      return;
      
    default:
      /* list */
      if((lp = EXPR_LIST(x)) == NULL){
        fprintf(print_fp,")");
        return;
      }
      for(/* */; lp != NULL; lp = lp->next) {
        fprintf(print_fp,"\n");
        expr_print_rec(print_fp, lp->expr,l+1);
      }
      fprintf(print_fp,")");
      break;
    }
}


void 
GenExpr :: print(FILE *fp)
{
  expr_print_rec(fp, this, 0);
  fprintf(fp,"\n");
}


GenExpr * ninf::gen::list0(GenExprCode code){
  return new GenExpr(code);
}

GenExpr * ninf::gen::list1(GenExprCode code, GenExpr * x1){
  return new GenExpr(code, new GenExprList(x1, NULL));
}

GenExpr * ninf::gen::list2(GenExprCode code, GenExpr * x1, GenExpr * x2){
  return new GenExpr(code, new GenExprList(x1, new GenExprList(x2, NULL)));
}

GenExpr * ninf::gen::list3(GenExprCode code, GenExpr * x1, GenExpr * x2, 
		   GenExpr * x3){
  return new GenExpr(code, new GenExprList(x1, new GenExprList(x2, new GenExprList(x3, NULL))));
}

GenExpr * ninf::gen::list4(GenExprCode code, GenExpr * x1, GenExpr * x2, 
		   GenExpr * x3, GenExpr * x4){
  return new GenExpr(code, 
      new GenExprList(x1, new GenExprList(x2, new GenExprList(x3, new GenExprList(x4, NULL)))));
}


GenExpr * ninf::gen::list_put_last(GenExpr * lx, GenExpr * x){
  GenExprList * lp = lx->v.lp;
  if(lp == NULL)
    lx->v.lp = new GenExprList(x,NULL);
  else {
    for(; lp->next != NULL; lp = lp->next) /* */;
    lp->next = new GenExprList(x,NULL);
  }
  return(lx);
}


struct expr_code_info_table_t 
{
    GenExprCode code;
    const char *name;
} expr_code_info_table[] =
{
        {ERROR_NODE,"ERROR_NODE"},
        {LIST,"LIST"},
        {IDENT,"IDENT"},
        {STRING_CONSTANT,"STRING_CONSTANT"},
        {INT_CONSTANT,"INT_CONSTANT"},
        {LONG_CONSTANT,"LONG_CONSTANT"},
        {FLOAT_CONSTANT,"FLOAT_CONSTANT"},
        {BASIC_TYPE_NODE,"BASIC_TYPE_NODE"},
        {MODE_SPEC_NODE,"MODE_SPEC_NODE"},

        {PLUS_EXPR,"+"},
        {MINUS_EXPR,"-"},
        {UNARY_MINUS_EXPR,"unary-"},
        {MUL_EXPR,"*"},
        {DIV_EXPR,"/"},
        {MOD_EXPR,"%"},
        {BEKI_EXPR,"^"},

	{EQ_EXPR, "=="},
	{NEQ_EXPR, "!="},
	{GT_EXPR,  ">"},
	{LT_EXPR,  "<"},
	{GE_EXPR,  ">="}, 
	{LE_EXPR,  "<="},
        {TRY_EXPR, "? :"},

        {POINTER_REF,"POINTER_REF"},
        {ARRAY_REF,"ARRAY_REF"},
        {(GenExprCode)-1,NULL}
};

const char * 
EXPR_CODE_NAME(GenExprCode code){
  expr_code_info_table_t * table = expr_code_info_table;
  while (table->code >= 0){
    if (table->code == code)
      return table->name;
    table++;
  }
  return "";
}
